//
//  GYCharacteristic.m
//  LockManagement
//
//  Created by apple on 2018/7/30.
//  Copyright © 2018年 yunjiazhineng. All rights reserved.
//

#import "GYCharacteristic.h"
#import "GYPeriphreal.h"

#define kARRAYMAXCOUNT 5

@interface GYCharacteristic()

@property (nonatomic, strong, readwrite) GYPeriphreal *periphreal;

/** 写的操作 */
@property (nonatomic, strong) blueManagerCharacteristicOperationBlcok writeOperateCallback;

/** 写的操作 */
@property (nonatomic, strong) blueManagerCharacteristicOperationBlcok readOperateCallback;

/** 写的操作 */
@property (nonatomic, strong) blueManagerCharacteristicOperationBlcok notifyOperateCallback;

@property (nonatomic, strong) NSMutableArray *readDataArray ;
@property (nonatomic, strong) NSMutableArray *writeDataArray ;
@property (nonatomic, strong) NSMutableArray *notifyDataArray ;

@property (nonatomic,strong)NSMutableArray<blueManagerCharacteristicOperationBlcok> *readCallbackArray ;
@property (nonatomic,strong)NSMutableArray<blueManagerCharacteristicOperationBlcok> *writeCallbackArray ;
@property (nonatomic,strong)NSMutableArray<blueManagerCharacteristicOperationBlcok> *notifyCallbackArray ;
@end


@implementation GYCharacteristic


- (NSString *)name
{
    return [NSString stringWithFormat:@"%@",self.characteristic.UUID ];
}
- (CBUUID *)UUID
{
    return _characteristic.UUID;
}

- (CBCharacteristicProperties)properties
{
    return _characteristic.properties;
}
- (NSData *)value
{
    return _characteristic.value ;
}
- (BOOL)isNotifying
{
    return _characteristic.isNotifying ;
}


-(NSString *)propertiesString
{
    CBCharacteristicProperties temProperties = self.properties;
    
    NSMutableString *tempString = [NSMutableString string];
    
    if (temProperties & CBCharacteristicPropertyBroadcast) {
        [tempString appendFormat:@"Broadcast "];
    }
    if (temProperties & CBCharacteristicPropertyRead) {
        [tempString appendFormat:@"Read "];
    }
    if (temProperties & CBCharacteristicPropertyWriteWithoutResponse) {
        [tempString appendFormat:@"WriteWithoutResponse "];
    }
    if (temProperties & CBCharacteristicPropertyWrite) {
        [tempString appendFormat:@"Write "];
    }
    if (temProperties & CBCharacteristicPropertyNotify) {
        [tempString appendFormat:@"Notify "];
    }
    if (temProperties & CBCharacteristicPropertyIndicate)//notify
    {
        [tempString appendFormat:@"Indicate "];
    }
    if(temProperties & CBCharacteristicPropertyAuthenticatedSignedWrites)//indicate
    {
        [tempString appendFormat:@"AuthenticatedSignedWrites "];
    }
    if (tempString.length > 1) {
        [tempString replaceCharactersInRange:NSMakeRange(tempString.length-1, 1) withString:@""];
    }
    return tempString ;
}

- (instancetype)initWithCharacteristic:(CBCharacteristic *)character
{
    return [self initWithCharacteristic:character perpheral:self.periphreal];
}
- (instancetype)initWithCharacteristic:(CBCharacteristic *)character perpheral:(GYPeriphreal *)peripheral
{
    if (self = [super init]) {
        self.characteristic = character ;
        self.periphreal = peripheral ;
    }
    return self;
}

- (void)writeValueWithByte:(int8_t)byte callback:(blueManagerCharacteristicOperationBlcok)callback
{
    NSAssert(byte, @"byte is null , you can't send a empty data to device");
    NSData *data = [[NSData alloc]initWithBytes:&byte length:1];
    [self writeValueWithData:data callback:callback];
}

- (void)writeValueWithData:(NSData *)data callback:(blueManagerCharacteristicOperationBlcok)callback
{
    NSAssert(data, @"byte is null , you can't send a empty data to device");
    
    if (data) {
        [self addDataToArrayWithType:operationTypeWrite data:data];
    }
    
    if (callback) {
        _writeOperateCallback = [callback copy];
    }
    
    CBCharacteristicWriteType writeType = callback ? CBCharacteristicWriteWithResponse : CBCharacteristicWriteWithoutResponse ;
    
    for (int i = 0; i < data.length; i+=20) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        dispatch_queue_t currentQueue = dispatch_get_current_queue() ;
#pragma clang diagnostic pop
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((i/20)*0.2 * NSEC_PER_SEC)), currentQueue, ^{
            
            NSUInteger subLength = data.length - i > 20 ? 20 : data.length-i ;
            NSData *subData = [data subdataWithRange:NSMakeRange(i, subLength)];
            
            NSLog(@"往特征上写数据 %@ %@",self.characteristic.UUID,subData);
            [self.periphreal.periphreal writeValue:subData
                                 forCharacteristic:self.characteristic
                                              type:writeType];
        });
    }
}

//#warning ====需要一个写入队列
- (void)readValueWithCallback:(blueManagerCharacteristicOperationBlcok)callback
{
    if (callback) {
        
        _readOperateCallback = [callback copy];
    }
    NSLog(@"读取特征上的数据 %@",self.characteristic.UUID);
    [self.periphreal.periphreal readValueForCharacteristic:self.characteristic];
    
}

- (void)notifyWithValue:(BOOL)value callback:(blueManagerCharacteristicOperationBlcok)callback
{
    if (callback) {
        _notifyOperateCallback = [callback copy];
    }
    
    if (self.periphreal) {
        
        NSLog(@"监听特征上的通知 %@ %d",self.characteristic.UUID,value);
        [self.periphreal.periphreal setNotifyValue:value forCharacteristic:self.characteristic];
    }
    else{
        NSLog(@"the peripheral is null !");
    }
}

- (void)dealOperationCharacterWithType:(OperationType)type error:(NSError *)error
{
    switch (type) {
        case operationTypeRead:
            if (_readOperateCallback) {
                _readOperateCallback(self,self.value,error);
                _readOperateCallback = nil ;
            }
            
            if (self.characteristic.value) {
                [self addDataToArrayWithType:operationTypeNotify data:self.value];
            }
            
            break;
        case operationTypeWrite:
            if (_writeOperateCallback) {
                _writeOperateCallback(self,self.value,error);
                _writeOperateCallback = nil ;
            }
            break ;
        case operationTypeNotify:
        {
            if (self.characteristic.value) {
                [self addDataToArrayWithType:operationTypeNotify data:self.value];
            }
            if (_notifyOperateCallback) {
                _notifyOperateCallback(self,self.value,error);
            }
        }break ;
            
        default:
            break;
    }
}

- (void)addDataToArrayWithType:(OperationType)type data:(NSData *)data
{
    NSAssert(data, @"can't add an empty object to array");
    
    switch (type) {
        case operationTypeWrite:
            if (self.writeDataArray.count >= kARRAYMAXCOUNT) {
                [self.writeDataArray removeLastObject];
            }
            [self.writeDataArray insertObject:data atIndex:0];
            break;
        case operationTypeRead:
            if (self.readDataArray.count >= kARRAYMAXCOUNT) {
                [self.readDataArray removeLastObject];
            }
            [self.readDataArray insertObject:data atIndex:0];
            break;
        case operationTypeNotify:
            if (self.notifyDataArray.count >= kARRAYMAXCOUNT) {
                [self.notifyDataArray removeLastObject];
            }
            [[self mutableArrayValueForKey:@"notifyDataArray"] insertObject:data atIndex:0];
            //            [self.notifyDataArray insertObject:data atIndex:0];
            break;
        default:
            break;
    }
    
}


- (NSMutableArray *)readDataArray
{
    if ( nil == _readDataArray) {
        _readDataArray = [NSMutableArray arrayWithCapacity:kARRAYMAXCOUNT];
    }
    return _readDataArray ;
}
- (NSMutableArray *)writeDataArray
{
    if (nil == _writeDataArray) {
        _writeDataArray = [NSMutableArray arrayWithCapacity:kARRAYMAXCOUNT];
    }
    return _writeDataArray ;
}

- (NSMutableArray *)notifyDataArray
{
    if (nil == _notifyDataArray) {
        _notifyDataArray = [NSMutableArray arrayWithCapacity:kARRAYMAXCOUNT];
    }
    return _notifyDataArray ;
}


@end
